#!/bin/sh /etc/rc.common
#
# Copyright (C) 2015 OpenWrt-dist
# Copyright (C) 2016 Chen RuiWei <crwbak@gmail.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#

START=90
STOP=15

CONFIG=shadowsocks
CONFIG_FILE=/var/etc/$CONFIG.json

uci_get_by_name() {
	local ret=$(uci get $CONFIG.$1.$2 2>/dev/null)
	echo ${ret:=$3}
}

uci_get_by_type() {
	local ret=$(uci get $CONFIG.@$1[0].$2 2>/dev/null)
	echo ${ret:=$3}
}

iptables_ext() {
	iptables -t nat -C $2 $3 2>/dev/null
	local ret=$?
	if [ "$ret" -ne 0 ];then
		iptables -t nat -$1 $2 $3 2>/dev/null
	fi
}

gen_config_file() {
	cat <<-EOF >$CONFIG_FILE
		{
		    "server": "$(uci_get_by_name $1 server)",
		    "server_port": $(uci_get_by_name $1 server_port),
		    "local_address": "0.0.0.0",
		    "local_port": $(uci_get_by_name $1 local_port),
		    "password": "$(uci_get_by_name $1 password)",
		    "timeout": $(uci_get_by_name $1 timeout 60),
		    "method": "$(uci_get_by_name $1 encrypt_method)"
		}
EOF
}

load_config() {
	GLOBAL_SERVER=$(uci_get_by_type global global_server nil)
	if [ $GLOBAL_SERVER = "nil" ]; then
		return $([ 1 -eq 0 ])
	fi
	PROXY_MODE=$(uci_get_by_type global proxy_mode gfwlist)
	DNS_MODE=$(uci_get_by_type global dns_mode ss-tunnel)
	DNS_FORWARD=$(uci_get_by_type global dns_forward 8.8.8.8:53)

	LOCAL_PORT=$(uci_get_by_name $GLOBAL_SERVER local_port)
	case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in
		1|on|true|yes|enabled) ARG_OTA="-A";;
		*) ARG_OTA="";;
	esac
	gen_config_file $GLOBAL_SERVER
	return $([ 1 -eq 1 ])
}

start_redir() {
	mkdir -p /var/run /var/etc
	/usr/bin/ss-redir \
	-c $CONFIG_FILE $ARG_OTA \
	-f /var/run/ss-redir.pid
}

start_dns() {
	case "$DNS_MODE" in
		ss-tunnel)
			/usr/bin/ss-tunnel \
			-c $CONFIG_FILE $ARG_OTA ${ARG_UDP:="-u"} \
			-l 5300 \
			-L $DNS_FORWARD \
			-f /var/run/ss-tunnel.pid
		;;
		dns2socks)
			/usr/bin/ss-local \
			-c $CONFIG_FILE $ARG_OTA \
			-f /var/run/ss-local.pid \
			-l 1081
			/usr/bin/dns2socks \
			127.0.0.1:1081 \
			$DNS_FORWARD \
			127.0.0.1:5300 \
			>/dev/null 2>&1 &
		;;
	esac
}

add_rule() {
	IPSET="vpn"
	iptables -t nat -N SHADOWSOCKS 2>/dev/null
	iptables_ext I PREROUTING "-j SHADOWSOCKS"
	case "$PROXY_MODE" in
		gfwlist)
			ipset -! create $IPSET iphash
			iptables_ext A SHADOWSOCKS "-p tcp -m set --match-set $IPSET dst -j REDIRECT --to $LOCAL_PORT"
			;;
		global)
			iptables_ext A SHADOWSOCKS "-d 0.0.0.0/8 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 10.0.0.0/8 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 127.0.0.0/8 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 169.254.0.0/16 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 172.16.0.0/12 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 192.168.0.0/16 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 224.0.0.0/4 -j RETURN"
			iptables_ext A SHADOWSOCKS "-d 240.0.0.0/4 -j RETURN"
			iptables_ext A SHADOWSOCKS "-p tcp -j REDIRECT --to $LOCAL_PORT"
		;;
	esac
}

del_rule() {
	iptables -t nat -D PREROUTING -j SHADOWSOCKS 2>/dev/null
	iptables -t nat -F SHADOWSOCKS 2>/dev/null
	iptables -t nat -X SHADOWSOCKS 2>/dev/null
}

start() {
	! load_config && exit 0
	start_redir
	start_dns
	add_rule
}

stop() {
	del_rule
	killall -q -9 ss-redir
	killall -q -9 ss-tunnel
	killall -q -9 ss-local
	killall -q -9 dns2socks
}
